package com.tsfyun.scm.service.impl.customer;

import cn.hutool.core.collection.CollUtil;
import com.github.pagehelper.PageInfo;
import com.google.common.collect.Lists;
import com.tsfyun.common.base.enums.QuoteTypeEnum;
import com.tsfyun.common.base.exception.ServiceException;
import com.tsfyun.common.base.extension.OrderItem;
import com.tsfyun.common.base.util.TsfPreconditions;
import com.tsfyun.scm.dto.customer.ExpressStandardQTO;
import com.tsfyun.scm.dto.customer.ExpressStandardQuoteDTO;
import com.tsfyun.scm.dto.customer.ExpressStandardQuoteMemberDTO;
import com.tsfyun.scm.dto.customer.ExpressStandardQuotePlusDTO;
import com.tsfyun.scm.entity.customer.ExpressStandardQuote;
import com.tsfyun.scm.entity.customer.ExpressStandardQuoteMember;
import com.tsfyun.scm.mapper.customer.ExpressStandardQuoteMapper;
import com.tsfyun.scm.service.customer.IExpressStandardQuoteMemberService;
import com.tsfyun.scm.service.customer.IExpressStandardQuoteService;
import com.tsfyun.common.base.extension.ServiceImpl;
import com.tsfyun.scm.util.ExpressQuoteUtil;
import com.tsfyun.scm.util.TsfWeekendSqls;
import com.tsfyun.scm.vo.customer.ExpressStandardQuoteMemberVO;
import com.tsfyun.scm.vo.customer.ExpressStandardQuotePlusVO;
import com.tsfyun.scm.vo.customer.ExpressStandardQuoteVO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import tk.mybatis.mapper.entity.Example;

import java.time.LocalDateTime;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.IntStream;

/**
 * <p>
 * 快递模式标准报价代理费 服务实现类
 * </p>
 *
 *
 * @since 2020-10-26
 */
@Service
@Slf4j
public class ExpressStandardQuoteServiceImpl extends ServiceImpl<ExpressStandardQuote> implements IExpressStandardQuoteService {

    @Autowired
    private ExpressStandardQuoteMapper expressStandardQuoteMapper;
    @Autowired
    private IExpressStandardQuoteMemberService expressStandardQuoteMemberService;

    @Override
    public ExpressStandardQuote getExistsQuote(String quoteType) {
        List<ExpressStandardQuote> dataList = expressStandardQuoteMapper.selectByExample(Example.builder(ExpressStandardQuote.class).where(TsfWeekendSqls.<ExpressStandardQuote>custom().andEqualTo(false,ExpressStandardQuote::getQuoteType,quoteType)
                .andEqualTo(false,ExpressStandardQuote::getDisabled,Boolean.FALSE)
                .andLessThan(false,ExpressStandardQuote::getQuoteStartTime,LocalDateTime.now())
                .andGreaterThan(false,ExpressStandardQuote::getQuoteEndTime, LocalDateTime.now().plusDays(-1))).build());
        if(CollUtil.isEmpty(dataList)) {
            return null;
        }
        if(dataList.size() > 1) {
            log.error("存在多条启用的有效的标准报价");
            return null;
        }
        return dataList.get(0);
    }

    @Override
    public List<ExpressStandardQuoteMemberVO> getCurrentEffective(String quoteType) {
        ExpressStandardQuote expressStandardQuote = getExistsQuote(quoteType);
        if(Objects.isNull(expressStandardQuote)){
            throw new ServiceException("未找到有效的标准报价");
        }
        List<ExpressStandardQuoteMember> members = expressStandardQuoteMemberService.findByQuoteId(expressStandardQuote.getId());
        if(CollUtil.isEmpty(members)){
            throw new ServiceException("未找到有效的标准报价明细");
        }
        List<ExpressStandardQuoteMemberVO> list = Lists.newArrayList();
        members.stream().forEach(esqvo ->{
            ExpressStandardQuoteMemberVO vo = beanMapper.map(esqvo,ExpressStandardQuoteMemberVO.class);
            vo.setCapped(expressStandardQuote.getCapped());
            vo.setCappedFee(expressStandardQuote.getCappedFee());
            list.add(vo);
        });
        return list;
    }

    @Override
    public List<ExpressStandardQuote> getAllEffectiveStandardQuote() {
        List<ExpressStandardQuote> dataList = expressStandardQuoteMapper.selectByExample(Example.builder(ExpressStandardQuote.class).where(TsfWeekendSqls.<ExpressStandardQuote>custom()
                .andEqualTo(false,ExpressStandardQuote::getDisabled,Boolean.FALSE)
                .andGreaterThan(false,ExpressStandardQuote::getQuoteEndTime, LocalDateTime.now().plusDays(-1))).build());
        if(CollUtil.isEmpty(dataList)) {
            return null;
        }
        return dataList;
    }

    @Override
    public PageInfo<ExpressStandardQuote> pageList(ExpressStandardQTO qto) {
        TsfWeekendSqls sqls = TsfWeekendSqls.<ExpressStandardQuote>custom()
                .andEqualTo(true, ExpressStandardQuote::getQuoteType,qto.getQuoteType())
                .andEqualTo(true,ExpressStandardQuote::getDisabled,qto.getDisabled());
        return super.pageList(qto.getPage(),qto.getLimit(),sqls, Lists.newArrayList(OrderItem.desc("dateCreated")));
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void updateDisabled(String id, Boolean disabled) {
        ExpressStandardQuote expressStandardQuote = super.getById(id);
        TsfPreconditions.checkArgument(Objects.nonNull(expressStandardQuote),new ServiceException("代理费报价信息不存在"));

        ExpressStandardQuote update = new ExpressStandardQuote();
        update.setDisabled(disabled);
        expressStandardQuoteMapper.updateByExampleSelective(update, Example.builder(ExpressStandardQuote.class).where(
                TsfWeekendSqls.<ExpressStandardQuote>custom().andEqualTo(false,ExpressStandardQuote::getId, id)).build()
        );
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void addPlus(ExpressStandardQuotePlusDTO dto) {
        ExpressStandardQuoteDTO quoteDTO = dto.getQuote();
        List<ExpressStandardQuoteMemberDTO> quoteMembers = dto.getMembers();
        ExpressQuoteUtil.check(dto);
        //校验是否存在启用的当前业务类型的代理费报价信息（如果是禁用则不检查）
        if(!Objects.equals(Boolean.TRUE,quoteDTO.getDisabled())) {
            List<ExpressStandardQuote> dataList = expressStandardQuoteMapper.selectByExample(Example.builder(ExpressStandardQuote.class).where(TsfWeekendSqls.<ExpressStandardQuote>custom().andEqualTo(false, ExpressStandardQuote::getQuoteType, quoteDTO.getQuoteType())
                    .andEqualTo(false, ExpressStandardQuote::getDisabled, Boolean.FALSE)
                    .andLessThan(false, ExpressStandardQuote::getQuoteStartTime, LocalDateTime.now())
                    .andGreaterThan(false, ExpressStandardQuote::getQuoteEndTime, LocalDateTime.now().plusDays(-1))).build());
            if (CollUtil.isNotEmpty(dataList)) {
                throw new ServiceException(String.format("已存在生效中的业务类型【%s】的报价信息", QuoteTypeEnum.of(quoteDTO.getQuoteType()).getName()));
            }
        }
        ExpressStandardQuote expressStandardQuote = new ExpressStandardQuote();
        expressStandardQuote.setName(quoteDTO.getName());
        expressStandardQuote.setQuoteType(quoteDTO.getQuoteType());
        expressStandardQuote.setDisabled(Objects.equals(quoteDTO.getDisabled(),Boolean.TRUE));
        expressStandardQuote.setQuoteStartTime(quoteDTO.getQuoteStartTime());
        expressStandardQuote.setQuoteEndTime(quoteDTO.getQuoteEndTime());
        expressStandardQuote.setCapped(quoteDTO.getCapped());
        expressStandardQuote.setCappedFee(!Objects.equals(expressStandardQuote.getCapped(),Boolean.TRUE) ? null : quoteDTO.getCappedFee());
        super.saveNonNull(expressStandardQuote);

        //批量保存报价明细
        expressStandardQuoteMemberService.addBatch(expressStandardQuote.getId(),quoteMembers);
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void editPlus(ExpressStandardQuotePlusDTO dto) {
        ExpressStandardQuoteDTO quoteDTO = dto.getQuote();
        List<ExpressStandardQuoteMemberDTO> quoteMembers = dto.getMembers();
        ExpressQuoteUtil.check(dto);
        ExpressStandardQuote expressStandardQuote = super.getById(quoteDTO.getId());
        Optional.ofNullable(expressStandardQuote).orElseThrow(()->new ServiceException("代理费报价信息不存在"));
        //校验是否存在启用的当前业务类型的代理费报价信息（如果是禁用则不检查）
        if(!Objects.equals(Boolean.TRUE,quoteDTO.getDisabled())) {
            List<ExpressStandardQuote> dataList = expressStandardQuoteMapper.selectByExample(Example.builder(ExpressStandardQuote.class).where(TsfWeekendSqls.<ExpressStandardQuote>custom().andEqualTo(false, ExpressStandardQuote::getQuoteType, quoteDTO.getQuoteType())
                    .andEqualTo(false, ExpressStandardQuote::getDisabled, Boolean.FALSE)
                    .andLessThan(false, ExpressStandardQuote::getQuoteStartTime, LocalDateTime.now())
                    .andGreaterThan(false, ExpressStandardQuote::getQuoteEndTime, LocalDateTime.now().plusDays(-1))
                    .andNotEqualTo(false, ExpressStandardQuote::getId, quoteDTO.getId())).build());
            if (CollUtil.isNotEmpty(dataList)) {
                throw new ServiceException(String.format("已存在生效中的业务类型【%s】的报价信息", QuoteTypeEnum.of(quoteDTO.getQuoteType()).getName()));
            }
        }
        //区分明细的增删改
        //查询当前报价的报价明细
        List<ExpressStandardQuoteMember> members = expressStandardQuoteMemberService.findByQuoteId(quoteDTO.getId());
        Map<Long,ExpressStandardQuoteMember> memberMap = members.stream().collect(Collectors.toMap(ExpressStandardQuoteMember::getId, Function.identity()));
        IntStream.range(0,quoteMembers.size()).forEach(idx->{
            ExpressStandardQuoteMemberDTO memberDTO = quoteMembers.get(idx);
            ExpressStandardQuoteMember expressStandardQuoteMember;
            if(Objects.nonNull(memberDTO.getId())) {
                //修改
                expressStandardQuoteMember = memberMap.get(memberDTO.getId());
                Optional.ofNullable(expressStandardQuoteMember).orElseThrow(()->new ServiceException(String.format("第%s行报价明细信息不存在，请刷新页面重试",idx + 1)));
                //移除，剩余的即可当做是删除的数据
                memberMap.entrySet().removeIf(r->Objects.equals(r.getKey(),memberDTO.getId()));
            } else {
                //新增
                expressStandardQuoteMember = new ExpressStandardQuoteMember();
                expressStandardQuoteMember.setQuoteId(quoteDTO.getId());
            }
            expressStandardQuoteMember.setStartWeight(memberDTO.getStartWeight());
            expressStandardQuoteMember.setEndWeight(memberDTO.getEndWeight());
            expressStandardQuoteMember.setBasePrice(memberDTO.getBasePrice());
            expressStandardQuoteMember.setPrice(memberDTO.getPrice());
            if(Objects.nonNull(memberDTO.getId())) {
                expressStandardQuoteMemberService.updateById(expressStandardQuoteMember);
            } else {
                expressStandardQuoteMemberService.saveNonNull(expressStandardQuoteMember);
            }
        });

        //删除多余的报价明细
        List<Long> needRemoveIds = Lists.newArrayList();
        memberMap.entrySet().stream().forEach(k->{
            needRemoveIds.add(k.getKey());
        });
        if(CollUtil.isNotEmpty(needRemoveIds)) {
            expressStandardQuoteMemberService.removeByIds(needRemoveIds);
        }

        expressStandardQuote.setName(quoteDTO.getName());
        expressStandardQuote.setQuoteType(quoteDTO.getQuoteType());
        expressStandardQuote.setDisabled(Objects.equals(quoteDTO.getDisabled(),Boolean.TRUE));
        expressStandardQuote.setQuoteStartTime(quoteDTO.getQuoteStartTime());
        expressStandardQuote.setQuoteEndTime(quoteDTO.getQuoteEndTime());
        expressStandardQuote.setCapped(quoteDTO.getCapped());
        expressStandardQuote.setCappedFee(!Objects.equals(expressStandardQuote.getCapped(),Boolean.TRUE) ? null : quoteDTO.getCappedFee());
        super.updateById(expressStandardQuote);
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void delete(Long id) {
        ExpressStandardQuote expressStandardQuote = super.getById(id);
        Optional.ofNullable(expressStandardQuote).orElseThrow(()->new ServiceException("代理费报价信息不存在"));
        expressStandardQuoteMemberService.removeByQuoteId(id);
        super.removeById(id);
    }

    @Override
    public ExpressStandardQuotePlusVO detail(Long id) {
        ExpressStandardQuote expressStandardQuote = super.getById(id);
        Optional.ofNullable(expressStandardQuote).orElseThrow(()->new ServiceException("代理费报价信息不存在"));
        List<ExpressStandardQuoteMember> members = expressStandardQuoteMemberService.findByQuoteId(id);
        return new ExpressStandardQuotePlusVO(beanMapper.map(expressStandardQuote, ExpressStandardQuoteVO.class),
                beanMapper.mapAsList(members,ExpressStandardQuoteMemberVO.class));
    }
}
